package main.java.org.com;

import com.alibaba.fastjson.JSON;
import org.apache.ibatis.mapping.ResultMapping;
import org.mybatis.dynamic.sql.BasicColumn;
import org.mybatis.dynamic.sql.SqlColumn;
import org.mybatis.dynamic.sql.SqlTable;
import org.mybatis.generator.api.*;
import org.mybatis.generator.config.*;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.mybatis.generator.internal.JDBCConnectionFactory;
import org.mybatis.generator.internal.ObjectFactory;
import org.mybatis.generator.internal.db.DatabaseIntrospector;

import java.io.IOException;
import java.sql.Connection;
import java.sql.JDBCType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


public class Main {

    public static void main(String[] args) throws SQLException, InterruptedException, XMLParserException, IOException, InvalidConfigurationException, ClassNotFoundException {
        List<IntrospectedTable> list  =  introspectedTableList("wps_user");
        System.out.println(list);
       // generatorBaseResultMapping();
       // ;
       // test();
    }
    public static void test() throws XMLParserException, IOException, InvalidConfigurationException, SQLException, InterruptedException {
        List<String> warnings = new ArrayList<>();
        boolean overwrite = true;
        // 指定逆向工程配置文件
        Configuration config = getConfig();
        String co = JSON.toJSONString(config);
        Context context = config.getContext("ttTables");

        TableConfiguration tableConfiguration =  new TableConfiguration(context);
        tableConfiguration.setTableName("sys_config");
        context.addTableConfiguration(tableConfiguration);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);

    }


    private static Connection getConnection(Context context ) throws SQLException {
        ConnectionFactory connectionFactory;
        if (context.getJdbcConnectionConfiguration() != null) {
            connectionFactory = new JDBCConnectionFactory(context.getJdbcConnectionConfiguration());
        } else {
            connectionFactory = ObjectFactory.createConnectionFactory(context);
        }
        return connectionFactory.getConnection();
    }
    private static Configuration getConfig() {
        Configuration config  =  new Configuration();

        Context context =  new Context(ModelType.CONDITIONAL);
        context.setId("ttTables");
        context.setTargetRuntime("MyBatis3");
        JDBCConnectionConfiguration jdbcConnectionConfiguration = getJdbcConnectionConfiguration();
        context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);

        JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = getJavaModelGeneratorConfiguration();
        context.setJavaModelGeneratorConfiguration(javaModelGeneratorConfiguration);

        SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = getSqlMapGeneratorConfiguration();
        context.setSqlMapGeneratorConfiguration(sqlMapGeneratorConfiguration);

        JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = getJavaClientGeneratorConfiguration();
        context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);

        config.addContext(context);
        return config;
    }

    private static JDBCConnectionConfiguration getJdbcConnectionConfiguration(){
        JDBCConnectionConfiguration jdbcConnectionConfiguration =  new JDBCConnectionConfiguration();
        jdbcConnectionConfiguration.setConnectionURL("jdbc:mysql://localhost:3306/test");
        jdbcConnectionConfiguration.setDriverClass("com.mysql.cj.jdbc.Driver");
        jdbcConnectionConfiguration.setUserId("root");
        jdbcConnectionConfiguration.setPassword("root");
        return jdbcConnectionConfiguration;
    }

    private static JavaModelGeneratorConfiguration getJavaModelGeneratorConfiguration() {
        JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = new JavaModelGeneratorConfiguration();
        javaModelGeneratorConfiguration.setTargetPackage("com.example.business.test");
        javaModelGeneratorConfiguration.setTargetProject("./src/main/java");

//             <!-- enableSubPackages:是否让schema作为包的后缀 -->
//            <property name="enableSubPackages" value="false" />
//            <!-- 从数据库返回的值被清理前后的空格 -->
//            <property name="trimStrings" value="true" />
        javaModelGeneratorConfiguration.addProperty("enableSubPackages","false");
        javaModelGeneratorConfiguration.addProperty("trimStrings","true");
        return javaModelGeneratorConfiguration;

    }


//    <javaClientGenerator type="XMLMAPPER"
//    targetPackage="com.example.mapper"
//    targetProject="./src/main/java">
//            <!-- enableSubPackages:是否让schema作为包的后缀 -->
//            <property name="enableSubPackages" value="false" />
//        </javaClientGenerator>

    private static  JavaClientGeneratorConfiguration getJavaClientGeneratorConfiguration() {
        JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();
        javaClientGeneratorConfiguration.setTargetPackage("com.example.business.test");
        javaClientGeneratorConfiguration.setTargetProject("./src/main/java");
        javaClientGeneratorConfiguration.setConfigurationType("MAPPER");
        javaClientGeneratorConfiguration.addProperty("enableSubPackages","false");
        return javaClientGeneratorConfiguration;
    }

//    <sqlMapGenerator targetPackage="com.example.mapper"
//    targetProject="./src/main/resources">
//            <!-- enableSubPackages:是否让schema作为包的后缀 -->
//            <property name="enableSubPackages" value="false" />
//        </sqlMapGenerator>

    private static SqlMapGeneratorConfiguration getSqlMapGeneratorConfiguration(){
        SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = new SqlMapGeneratorConfiguration();
        sqlMapGeneratorConfiguration.setTargetPackage("com.example.business.test.mapper");
        sqlMapGeneratorConfiguration.setTargetProject("./src/main/resources");
        sqlMapGeneratorConfiguration.addProperty("enableSubPackages","false");
        return sqlMapGeneratorConfiguration;
    }



    public static List<ResultMapping>  generatorBaseResultMapping(org.apache.ibatis.session.Configuration configuration,String tableName) throws SQLException, ClassNotFoundException {
        List<IntrospectedTable> list = introspectedTableList(tableName);
        List<ResultMapping>  resultMappings =  new ArrayList<>();
        for(IntrospectedTable introspectedTable:list){

            for(IntrospectedColumn column:introspectedTable.getBaseColumns()) {
                //
               Class<?> javaType =  Class.forName(column.getFullyQualifiedJavaType().getFullyQualifiedName());
               ResultMapping.Builder builder =  new ResultMapping.Builder(configuration,column.getJavaProperty(),column.getActualColumnName(), javaType);
               ResultMapping resultMapping =  builder.build();
               resultMappings.add(resultMapping);
            }
            for(IntrospectedColumn column:introspectedTable.getPrimaryKeyColumns()) {
                //
                Class<?> javaType =  Class.forName(column.getFullyQualifiedJavaType().getFullyQualifiedName());
                ResultMapping.Builder builder =  new ResultMapping.Builder(configuration,column.getJavaProperty(),column.getActualColumnName(), javaType);
                ResultMapping resultMapping =  builder.build();
                resultMappings.add(resultMapping);
            }

        }
        return resultMappings;
    }

    public static List<IntrospectedTable> introspectedTableList(String tableName) throws SQLException {
        Context context = getConfig().getContext("ttTables");
        DefaultShellCallback callback = new DefaultShellCallback(true);
        List<String> warnings = new ArrayList<>();
        TableConfiguration tableConfiguration =  new TableConfiguration(context);
        tableConfiguration.setTableName(tableName);
        context.addTableConfiguration(tableConfiguration);

        Connection connection = getConnection(context);

        JavaTypeResolver javaTypeResolver = ObjectFactory
                .createJavaTypeResolver(context, warnings);
        DatabaseIntrospector databaseIntrospector = new DatabaseIntrospector(
                context, connection.getMetaData(), javaTypeResolver, warnings);

        List<IntrospectedTable> list = databaseIntrospector.introspectTables(tableConfiguration);
        //context.introspectTables( new NullProgressCallback(), warnings,null);
        return list;
    }


    public static DynamicSqlTable getSqlTable(String tableName) throws SQLException {

        List<IntrospectedTable>  list =    introspectedTableList(tableName);
        return new DynamicSqlTable(tableName,list);

    }


    public static class   DynamicSqlTable extends SqlTable {

        public final List<SqlColumn<?>> baseColumn = new ArrayList<>();
        public final List<SqlColumn<?>> keyColumn = new ArrayList<>();

        public BasicColumn[] getSelectColumn(){
            List<SqlColumn<?>> list =  new ArrayList<>();
            list.addAll(baseColumn);
            list.addAll(keyColumn);
            SqlColumn []  sqlColumns =  new SqlColumn[list.size()];
            sqlColumns =  list.toArray(sqlColumns);
           return BasicColumn.columnList(sqlColumns);

        }
        public List<SqlColumn<?>> getBaseColumn() {
            return baseColumn;
        }

        public List<SqlColumn<?>> getKeyColumn() {
            return keyColumn;
        }

        public DynamicSqlTable(String tableName, List<IntrospectedTable>list) {
            super(tableName);
            for(IntrospectedTable introspectedTable :list){
               List<IntrospectedColumn>  keyColumns =  introspectedTable.getPrimaryKeyColumns();
               for(IntrospectedColumn introspectedColumn :  keyColumns){
                  SqlColumn sqlColumn =  SqlColumn.of(introspectedColumn.getActualColumnName(), this, JDBCType.valueOf(introspectedColumn.getJdbcType()));
                  keyColumn.add(sqlColumn);
               }
               for(IntrospectedColumn introspectedColumn :introspectedTable.getBaseColumns()){
                   SqlColumn sqlColumn =  SqlColumn.of(introspectedColumn.getActualColumnName(), this, JDBCType.valueOf(introspectedColumn.getJdbcType()));
                   baseColumn.add(sqlColumn);
               }
            }
        }
    }
}